package Model.alignments;

import java.util.ArrayList;
import java.util.List;

import Model.ValidPosition;

public abstract class CollapsedAlignment extends SingleAlignment implements
		Subset0Alignment {
	public static final int COLLAPSE_WIGGLE = 32;

	protected List<Subset0Alignment> containedAlignments;
	protected int referencePosition;
	protected ValidPosition bounds;

	public CollapsedAlignment(Subset0Alignment a) {
		containedAlignments = new ArrayList<Subset0Alignment>();
		containedAlignments.add(a);
		calculateBounds();
	}

	@Override
	public ValidPosition getMaxBound() {
		if (bounds == null)
			calculateBounds();
		return bounds;
	}

	private void calculateBounds() {
		if (getAligmentCount() == 0)
			return;

		int start = Integer.MAX_VALUE;
		int end = Integer.MIN_VALUE;

		for (Subset0Alignment a : containedAlignments) {
			ValidPosition b = a.getMaxBound();
			start = (start > b.start) ? b.start : start;
			end = (end < b.end) ? b.end : end;
		}

		bounds = new ValidPosition(start, end);
	}

	public int getAligmentCount() {
		return containedAlignments.size();
	}

	public int getReferencePosition() {
		return referencePosition;
	}

	public static boolean isCandidateAddition(Subset0Alignment one,
			Subset0Alignment two) {
		// TODO: Figure out when this is called...
		if (one instanceof CollapsedAlignment
				&& two instanceof CollapsedAlignment)
			return false; // Two collapsed alignments can't combine together..

		if (one instanceof CollapsedAlignment)
			return ((CollapsedAlignment) one).isCandidateAddition(two);
		if (two instanceof CollapsedAlignment)
			return ((CollapsedAlignment) two).isCandidateAddition(one);

		// Both alignments are individual alignments
		if (!(one.getClass().toString().equals(two.getClass().toString())))
			return false;

		// Both alignments are the same type...
		if (one instanceof SpliceAlignment) {
			int spliceStartOne = one.getValidPositions().get(1).start;
			int spliceStartTwo = two.getValidPositions().get(1).start;
			return (Math.abs(spliceStartTwo - spliceStartOne) <= COLLAPSE_WIGGLE);
		}

		// Both are intron retention alignments
		return (Math.abs(one.getStart() - two.getStart()) <= COLLAPSE_WIGGLE);
	}

	public abstract void updateReferencePosition();

	public boolean addAlignment(Subset0Alignment temp) {
		if (!isCandidateAddition(temp))
			return false;

		containedAlignments.add(temp);
		return true;
	}

	abstract boolean isCandidateAddition(Subset0Alignment temp);
}
